/*
 * Copyright 2013 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');
var path = require('path');

function removeDupEmptyLines(list) {
  var lastWasEmpty = false;
  var result = [];
  list.forEach(function (s) {
    if (s === '') {
      if (!lastWasEmpty) {
        result.push('');
        lastWasEmpty = true;
      }
    } else {
      result.push(s);
      lastWasEmpty = false;
    }
  });
  return result;
}

function updateLibRefs(filePath, manifestPath, lib, onlyIncludes) {
  var content = fs.readFileSync(filePath, 'utf8');
  var m = new RegExp('\\n([\\t\\u0020]+)<!-- Autogenerated ' + lib + ' references: base=(\\S*)').exec(content);
  if (!m) {
    throw new Error(filePath + ' has no ' + lib + ' references');
  }

  var baseUrl = m[2], indent = m[1];
  var lineStart = indent + '<script src="' + baseUrl;
  var lineEnd = '"></script>';

  var entries = fs.readFileSync(manifestPath).toString().split(/\r?\n/g);

  content = content.replace(new RegExp('(Autogenerated ' + lib + ' references:.*?\\n)[\\S\\s]*?(\\n[ \t]+<!-- Autogenerated ' + lib + ' references end)'),
    function (all, head, tail) {
      return head + removeDupEmptyLines(entries.map(function (entry) {
        if (entry.trim() === '') {
          return '';
        }
        if (entry[0] !== '#') {
          return indent + '<script src="' + baseUrl + entry + '"></script>';
        }
        if (onlyIncludes) {
          return '';
        }
        if (entry[1] === '!') {
          if (entry.indexOf('#!inline ') === 0) {
            return indent + '<script> ' + entry.substr(9).trim() + ' </script>';
          }
          if (entry.indexOf('#!skipbundle ') === 0) {
            return indent + '<script src="' + baseUrl + entry.substr(13).trim() + '"></script>';
          }
          console.error('Skipping unknown ' + entry);
          return '';
        }
        if (entry[1] === '#') {
          return indent + '<!-- ' + entry.substr(2).trim() + ' -->';
        }
        if (entry[1] !== ' ') {
          return indent + '<!--<script src="' + baseUrl + entry.substr(1) + '"></script>-->';
        }
        return '';
      })).join('\n') + tail;
    }
  );

  fs.writeFileSync(filePath, content, 'utf8');
}

function updateJSLibRefs(filePath, manifestPath, lib, onlyIncludes) {
  var content = fs.readFileSync(filePath, 'utf8');
  var m = new RegExp('\\/\\* Autogenerated ' + lib + ' references: base=(\\S*)').exec(content);
  if (!m) {
    throw new Error(filePath + ' has no ' + lib + ' references');
  }

  var baseUrl = m[1], indent = "";

  var entries = fs.readFileSync(manifestPath).toString().split(/\r?\n/g);

  content = content.replace(new RegExp('(Autogenerated ' + lib + ' references:.*?\\n)[\\S\\s]*?(\\n\\/\\* Autogenerated ' + lib + ' references end)'),
    function (all, head, tail) {
      return head + removeDupEmptyLines(entries.map(function (entry) {
        if (entry.trim() === '') {
          return '';
        }
        if (entry[0] !== '#') {
          return indent + 'load("' + baseUrl + entry + '");';
        }
        if (onlyIncludes) {
          return '';
        }
        if (entry[1] === '!') {
          if (entry.indexOf('#!inline ') === 0) {
            return indent + entry.substr(9).trim();
          }
          if (entry.indexOf('#!skipbundle ') === 0) {
            return indent + 'load("' + baseUrl + entry.substr(13).trim() + '");';
          }
          console.error('Skipping unknown ' + entry);
          return '';
        }
        if (entry[1] === '#') {
          return indent + '// ' + entry.substr(2).trim();
        }
        if (entry[1] !== ' ') {
          return indent + '//' + baseUrl + entry.substr(1);
        }
        return '';
      })).join('\n') + tail;
    }
  );

  fs.writeFileSync(filePath, content, 'utf8');
}

function endsWith(string, value) {
  return string.substring(string.length - value.length, string.length) === value;
}

function removeJSLibDups(filePath) {
  var content = fs.readFileSync(filePath, 'utf8');
  var re = new RegExp('^load\\([^)]+\\);$', 'gm');
  var loaded = {};
  content = content.replace(re, function(all) {
    if (!loaded[all]) {
      loaded[all] = true;
      return all;
    }
    return '// DUP: ' + all;
  });
  fs.writeFileSync(filePath, content, 'utf8');
}

function removeLibDups(filePath) {
  var content = fs.readFileSync(filePath, 'utf8');
  var re = new RegExp('^(\\s*)(<script[^>]*><\/script>)(\\s*)$', 'gm');
  var loaded = {};
  content = content.replace(re, function(all, head, script, tail) {
    if (!loaded[script]) {
      loaded[script] = true;
      return all;
    }
    return head + '<!-- DUP: ' + script + ' -->' + tail;
  });
  fs.writeFileSync(filePath, content, 'utf8');
}

var homeBase = path.join(__dirname, '../');
var packageFilesBase = path.join(homeBase, 'src/');

function updateRefs(filePath, options) {
  var isJS = endsWith(filePath, ".js") || endsWith(filePath, ".ts");
  var onlyIncludes = !!options.onlyIncludes;
  var updateFn = isJS ? updateJSLibRefs : updateLibRefs;
  if (options.gfx) {
    updateFn(filePath, path.join(packageFilesBase, '/shumway.gfx.package'), 'gfx', onlyIncludes);
  }
  if (options.player) {
    updateFn(filePath, path.join(packageFilesBase, '/shumway.player.package'), 'player', onlyIncludes);
  }
  if (isJS) {
    removeJSLibDups(filePath);
  } else {
    removeLibDups(filePath);
  }
}
module.exports.updateRefs = updateRefs;

function packageRefs(includes, output, license) {
  var refs = '';
  includes.forEach(function (manifest) {
    refs += '## Manifest ' + manifest + '\n' +
      fs.readFileSync(path.join(packageFilesBase, '/shumway.' + manifest + '.package')) +
      '\n';
  });
  var content = '', included = {};
  refs.split('\n').forEach(function (entry) {
    if (entry.trim() === '') {
      return;
    }
    if (entry[0] !== '#') {
      if (included[entry]) {
        return; // skipping duplicates
      }
      included[entry] = true;
      content += fs.readFileSync(path.join(homeBase, entry)) + '\n';
      return;
    }
    if (entry[1] === '!') {
      if (entry.indexOf('#!inline ') === 0) {
        content += entry.substr(9).trim() + '\n';
        return;
      }
      if (entry.indexOf('#!skipbundle ') === 0) {
        return;
      }
      console.error('Skipping unknown ' + entry);
      return;
    }
    if (entry[1] === '#') {
      content += '// ' + entry.substr(2).trim() + '\n';
      return;
    }
  });
  fs.writeFileSync(output, license + content);
}

module.exports.packageRefs = packageRefs;
